//
//  KLineData.h
//  Chart
//
//  Created by CaoJun on 13-6-17.
//
//

#ifndef __Chart__KLineData__
#define __Chart__KLineData__

#include "YTXTime.h"
#include "AVGData.h"
#include "IndexData.h"
#include "IndexConfig.h"
#include "IndexConfigInterface.h"
#include "UserGraphInterface.h"
#include "config.h"
#include "YTXChartTools.h"
#include "json.h"

#include <list>
#include <tuple>
#include <string>
#include <vector>

namespace ytx {

    class KLineOption
    {
    public:

        std::string limit;
        std::string sort;
        std::string tradedate;
        std::string tradeEndDate;
        bool isCalculate;

        KLineOption(std::string tradedate, std::string tradeEndDate, std::string limit, std::string sort, bool isCalculate = false);
        KLineOption(bool isCalculate);

    };
    
    /**
     *  price(double), weight(double), isLong(bool)
     */
    typedef std::tuple<double, double, bool> HoldingPositionInfo;

    class KLineData : public Quotation, public IndexConfigInterface, public UserGraphInterface, public Observable<KLineData>
    {
    private:
        std::list<HoldingPositionInfo> holdingPositionInfos;
        
    public:
        KLineData(std::string id, std::string currentDate, LineType::LineType quotationType, std::string marketType, int toFix, std::string name, std::string nickName, bool hasVolume, int limit, int threshold, int buffer, YTXTime tradedate);
        virtual ~KLineData();

        bool dataEmptyFlagFrom;
        bool dataEmptyFlagTo;
        std::string tradedateTo;
        std::string tradedateFrom;

        IndexType::IndexType indexType;

        virtual KLineData * getObservable();

        virtual void firstFailRequestHandler(std::string tag);
        
        virtual void callback(std::string tag, std::string data);
        
        virtual void onFail(std::string tag);
        
        virtual void requestData(const std::string tag, const DataOption & dataOption, const std::string acceptableContent);

        virtual bool hasData() const;
        virtual bool hasData(int index) const;
        bool hasDataWithoutClose() const;
        virtual UpDropStatus::UpDropStatus getUpDropStatus(int index);
        virtual std::string getCrosshairYData(int index);
        virtual double getCrosshairXValue(int index);
        virtual std::pair<double, double> getDataMinMax(int startIndex, int endIndex) const;
        virtual std::pair<double, double> getAdjustedDataMinMax(int startIndex, int endIndex, const Rectangle & rect) const;
        virtual std::vector<std::pair<double, std::string> > getLeftSideText(int startIndex, int endIndex, const Rectangle & rect, const Style & style) const;
        virtual const std::vector<std::string> & getBottomSideText(SizeType::SizeType) const;

        void requestKLine(const KLineOption option, std::string tag = "requestKLineFrom");

        void getKFromTradeDateFrom(int limit);

        void getKFromTradeDateFrom();

        void getKFromTradeDateTo();

        virtual void getK();
        virtual void calculateTodayKLine();

        void responseKLine(YTXJson::Value data, YTXJson::Value info, std::string tag);

        KLineOption checkDataByTradedate(YTXTime dateTo) const;

        void calculateK();
        
        bool bufferIsEnough(int startIndex);

        void controlBuffer(int startIndex);

        YTXTime getTradedate(int index) const;
        YTXTime getTradedate() const;

        void update();

        int getLimit();
        void setLimit(int limit);
        int getThreshold();
        void setThreshold(int threshold);
        int getBuffer();
        void setBuffer(int buffer);

        void setLineInfo(IndexData *);

        virtual void intervalRequestDataInterface(){};

        virtual bool checkNeedGetNewK();

        virtual void getCloseNewK();

        virtual bool isInLatestNewK(YTXTime tradedate1, YTXTime tradedate2) = 0;

        virtual void listenOn();

        virtual void listenOff();

        virtual KLineItem getOCHL(std::vector<KLineItem>);

        virtual KLineItem getOCHL(std::vector<KLineItem>, double preClose);

        virtual KLineItem getOCHL(YTXTime limit1, YTXTime limit2);

        virtual KLineItem getOCHL(YTXTime limit);

        virtual KLineItem getOCHLByWeek(YTXTime now, YTXTimeDuration openTime);

        virtual KLineItem getOCHLByMonth(YTXTime now, YTXTimeDuration openTime);

        static bool compareHigh(KLineItem a, KLineItem b);
        static bool compareLow(KLineItem a, KLineItem b);

        virtual void cleanData();
        
        virtual void clearAllData();
        
        virtual UGCPoint getUserGraphWithPoint(float x1, float y1, Rectangle rect, int startIndex);
        
        virtual int getKLineItemIndexByDateTime(YTXTime time);
        
        bool isCacheInvalidation(YTXTime, YTXTime);
        
        virtual int getDataLengthWithoutClose() const;
        
        void setHoldingPositionInfos(const std::list<HoldingPositionInfo> &holdingPositionInfos);
        
        void addHoldingPositionInfo(const HoldingPositionInfo &holdingPositionInfo);
        
        void clearHoldingPositionInfos();
        
        const std::list<HoldingPositionInfo> & getHoldingPositionInfos() const;

    protected:
        std::vector<std::string> transDatesFromKLineItems(std::vector<KLineItem> & kLineItems);

        void setK(std::vector<KLineItem> &, std::vector<std::string> &);

        bool concatData(std::vector<KLineItem> & data, std::vector<std::string> & dateData);
        
        bool concatCloseNewData(std::vector<KLineItem> & data, std::vector<std::string> & dateData);

        bool bufferFlag;
        int limit;
        int threshold;
        int buffer;
        bool isDataEmptyFlag;
        bool closeDataFlag;

        KLineItem getLastItemWithoutClose() const;

        virtual unsigned int filterDataFrom(std::vector<KLineItem> & data, std::vector<std::string> & dates);
        
        virtual unsigned int filterDataTo(std::vector<KLineItem> & data, std::vector<std::string> & dates);
        
        void filterLastSameData();
    };
}

#endif /* defined(__Chart__KLineData__) */
